#ifndef __SUPERPIXEL_H
#define __SUPERPIXEL_H

#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <vector>
#include <cstdio>
#include <boost/thread/thread.hpp>
#include <iostream>
#include <stdio.h>
#include <boost/filesystem.hpp>

#define SPX_IS_LARGE 1000

class superpixel {
public:
    superpixel() {
        informative = 0;
        _size = 0;
        _good_sp = false;
        _large_enough = false;
        _matched = false;
    }

    int informative;

    //int area () {return (x[1]*x[2]);}
    void set_matchings(int, int, int, int);

    void set_color(int a, int b, int c) {
        _color[0] = a;
        _color[1] = b;
        _color[2] = c;
    };

    void set_contour(float, float, float);

    void set_contourR(cv::Mat contourR1) { _contour_r = contourR1.clone(); }

    void set_contour3D(cv::Mat contour3D1) { _contour_3d = contour3D1.clone(); }

    void set_pixels3D(cv::Mat pixels3D1) { _pixels_3d = pixels3D1.clone(); }

    void set_plane(float, float, float);

    void set_matrix(cv::Mat m1) { _m = m1.clone(); }

    void set_pixels(float, float, float);

    void setGood(bool good) { _good_sp = good; }// sup[i]->setGood(true)
    bool isGood() { return _good_sp; }

    void SetbAlreadyMatched(bool good) { _matched = good; } // sup[i]->SetbAlreadyMatched(true)
    bool bAlreadyMatched() { return _matched; }

    bool isLarge() { return _size > SPX_IS_LARGE; }

    void incSize() { _size++; }

    int getSize() { return _size; }

    cv::Mat getContour() { return _contour; }

    cv::Mat getContourR() { return _contour_r; }

    cv::Mat getContour3D() { return _contour_3d; }

    cv::Mat getMatchings() { return _matchings; }

    cv::Mat getPixels3D() { return _pixels_3d; }

    cv::Mat getPlane() { return _plane; }

    cv::Mat getMatrix() { return _m; }

    cv::Mat getPixels() { return _pixels; }

    cv::Mat _matchings;
    cv::Mat _plane;

private:

    bool _good_sp;
    bool _large_enough;
    bool _matched;
    cv::Mat _contour;
    cv::Mat _contour_r;
    cv::Mat _pixels;
    cv::Mat _contour_3d;
    cv::Mat _pixels_3d;
    int _size;
    int _color[3];
    cv::Mat _m;
};

class SuperpixelesImagen {
public:
    struct Data {
        cv::Mat R1;
        cv::Mat t1;
        float f1;
        float ka1;
        float kb1;
        int reduction;
    } Data1;

    SuperpixelesImagen() {}


    void set_data(cv::Mat R1, cv::Mat t1, float f1, float ka1, float kb1) {
        Data1.R1 = R1;
        Data1.t1 = t1;
        Data1.f1 = f1;
        Data1.ka1 = ka1;
        Data1.kb1 = kb1;
    }

    Data GetData() { return Data1; }

//    void cargar_imagen();

    /// this function compute superpixels and calculate the contours, used for 3D superpixel matching
    int computeSuperpixels();

    std::vector<superpixel *> getSuperpixeles() { return _sup; }

    int getNumberOfSuperpixels() { return _sup.size(); }

    std::vector<superpixel *> _sup;
    cv::Mat _image;
    char *_image_name;
    char *_sup_name;

private:

};

class Imagen {
public:

    Imagen() : _used_mapping(0) {}

    cv::Mat _accurate_sd_map;
    cv::Mat _image;
    cv::Mat _image_gray;
    cv::Mat _R;
    cv::Mat _t;
    cv::Mat _t_r;

    float _fx;
    float _fy;
    float _cx;
    float _cy;
    float _k1;
    float _k2;
    double _stamps;
    float _error;

    int _reduction;
    int _num_keyframes;
    int _used_mapping;
private:

};

class Imagenes {
public:
    Imagenes() {}

    void computeImage();

    void computeImageSup();

    int get_size() const { return _image_vec.size(); }

    int get_su_size() const { return _sup_image_vec.size(); }

    std::vector<SuperpixelesImagen *> getSuperpixelesImagen() { return _sup_image_vec; }

    std::vector<Imagen *> _image_vec;
    std::vector<SuperpixelesImagen *> _sup_image_vec;

private:


};


class PhotometricTerm {
public:

    PhotometricTerm() {}

    void computeError();

    std::vector<cv::Mat> _ph_error_vec;
private:
};


class MapShared : public Imagenes {
public:
    MapShared() {}

    void set_R(cv::Mat R_aux) { _R = R_aux.clone(); }

    cv::Mat get_R() { return _R; }

    void set_t(cv::Mat t_aux) { _t = t_aux.clone(); }

    cv::Mat get_t() { return _t; }

private:
    cv::Mat _R;
    cv::Mat _t;
    cv::Mat _superpixels_3d;

};

#endif
